/*     */
package com.yuns.util;
/*     */
/*     */

import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.io.resource.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
public class HttpsUtil
        extends DefaultHttpClient {
    public static final String HTTPGET = "GET";
    public static final String HTTPPUT = "PUT";
    public static final String HTTPPOST = "POST";
    public static final String HTTPDELETE = "DELETE";
    public static final String HTTPACCEPT = "Accept";
    public static final String CONTENT_LENGTH = "Content-Length";
    public static final String CHARSET_UTF8 = "UTF-8";
    private static HttpClient httpClient;

    public void initSSLConfigForTwoWay() throws Exception {
        try {
//        String demo_base_Path = System.getProperty("com.yuns.user.dir");
            Resource selfcertpathresource = new ClassPathResource(Constant.SELFCERTPATH);
//            String selfcertpath =selfcertpathresource.getUrl().getPath();
//            log.error(selfcertpath);
            Resource trustcapathresource = new ClassPathResource(Constant.TRUSTCAPATH);
//            String trustcapath =trustcapathresource.getUrl().getPath();
//            log.error(trustcapath);
////        String trustcapath = String.valueOf(demo_base_Path) + Constant.TRUSTCAPATH;
//            System.out.println("*************" + trustcapath);

            KeyStore selfCert = KeyStore.getInstance("pkcs12");
            selfCert.load(selfcertpathresource.getStream(),
                    Constant.SELFCERTPWD.toCharArray());
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509");
            kmf.init(selfCert, Constant.SELFCERTPWD.toCharArray());


            KeyStore caCert = KeyStore.getInstance("jks");
            caCert.load(trustcapathresource.getStream(), Constant.TRUSTCAPWD.toCharArray());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509");
            tmf.init(caCert);

            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);


            SSLSocketFactory ssf = new SSLSocketFactory(sc,
                    SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);


            ThreadSafeClientConnManager threadSafeClientConnManager = new ThreadSafeClientConnManager();
            SchemeRegistry sr = threadSafeClientConnManager.getSchemeRegistry();
            sr.register(new Scheme("https", 8743, (SchemeSocketFactory) ssf));
            httpClient = (HttpClient) new DefaultHttpClient((ClientConnectionManager) threadSafeClientConnManager);
        } catch (KeyStoreException e) {
          log.error(e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

    }


    public HttpResponse doPostJson(String url, Map<String, String> headerMap, String content) {
        HttpPost request = new HttpPost(url);
        addRequestHeader((HttpUriRequest) request, headerMap);
        request.setEntity((HttpEntity) new StringEntity(content,
                ContentType.APPLICATION_JSON));
        return executeHttpRequest((HttpUriRequest) request);
    }


    public StreamClosedHttpResponse doPostJsonGetStatusLine(String url, Map<String, String> headerMap, String content) {
        HttpPost request = new HttpPost(url);
        addRequestHeader((HttpUriRequest) request, headerMap);

        request.setEntity((HttpEntity) new StringEntity(content,
                ContentType.APPLICATION_JSON));

        HttpResponse response = executeHttpRequest((HttpUriRequest) request);
        if (response == null) {
            System.out.println("The response body is null.");
        }

        return (StreamClosedHttpResponse) response;
    }

    public StreamClosedHttpResponse doPostJsonGetStatusLine(String url, String content) {
        HttpPost request = new HttpPost(url);

        request.setEntity((HttpEntity) new StringEntity(content,
                ContentType.APPLICATION_JSON));

        HttpResponse response = executeHttpRequest((HttpUriRequest) request);
        if (response == null) {
            System.out.println("The response body is null.");
        }

        return (StreamClosedHttpResponse) response;
    }

    private List<NameValuePair> paramsConverter(Map<String, String> params) {
        List<NameValuePair> nvps = new LinkedList<>();
        Set<Map.Entry<String, String>> paramsSet = params.entrySet();
        for (Map.Entry<String, String> paramEntry : paramsSet) {
            nvps.add(new BasicNameValuePair(paramEntry.getKey(), paramEntry
                    .getValue()));
        }

        return nvps;
    }


    public StreamClosedHttpResponse doPostFormUrlEncodedGetStatusLine(String url, Map<String, String> formParams) throws Exception {
        HttpPost request = new HttpPost(url);

        request.setEntity((HttpEntity) new UrlEncodedFormEntity(paramsConverter(formParams)));

        HttpResponse response = executeHttpRequest((HttpUriRequest) request);
        if (response == null) {
            System.out.println("The response body is null.");
            throw new Exception();
        }

        return (StreamClosedHttpResponse) response;
    }


    public HttpResponse doPutJson(String url, Map<String, String> headerMap, String content) {
        HttpPut request = new HttpPut(url);
        addRequestHeader((HttpUriRequest) request, headerMap);

        request.setEntity((HttpEntity) new StringEntity(content,
                ContentType.APPLICATION_JSON));

        return executeHttpRequest((HttpUriRequest) request);
    }

    public HttpResponse doPut(String url, Map<String, String> headerMap) {
        HttpPut request = new HttpPut(url);
        addRequestHeader((HttpUriRequest) request, headerMap);
        return executeHttpRequest((HttpUriRequest) request);
    }


    public StreamClosedHttpResponse doPutJsonGetStatusLine(String url, Map<String, String> headerMap, String content) {
        HttpResponse response = doPutJson(url, headerMap, content);
        if (response == null) {
            System.out.println("The response body is null.");
        }

        return (StreamClosedHttpResponse) response;
    }

    public StreamClosedHttpResponse doPutGetStatusLine(String url, Map<String, String> headerMap) {
        HttpResponse response = doPut(url, headerMap);
        if (response == null) {
            System.out.println("The response body is null.");
        }

        return (StreamClosedHttpResponse) response;
    }


    public HttpResponse doGetWithParas(String url, Map<String, String> queryParams, Map<String, String> headerMap) throws Exception {
        URIBuilder builder;
        HttpGet request = new HttpGet();
        addRequestHeader((HttpUriRequest) request, headerMap);
        try {
            builder = new URIBuilder(url);
        } catch (URISyntaxException e) {
            System.out.printf("URISyntaxException: {}", new Object[]{e});
            throw new Exception(e);
        }


        if (queryParams != null && !queryParams.isEmpty()) {
            builder.setParameters(paramsConverter(queryParams));
        }
        request.setURI(builder.build());

        return executeHttpRequest((HttpUriRequest) request);
    }


    public StreamClosedHttpResponse doGetWithParasGetStatusLine(String url, Map<String, String> queryParams, Map<String, String> headerMap) throws Exception {
        HttpResponse response = doGetWithParas(url, queryParams, headerMap);
        if (response == null) {
            System.out.println("The response body is null.");
        }

        return (StreamClosedHttpResponse) response;
    }

    public HttpResponse doDelete(String url, Map<String, String> headerMap) {
        HttpDelete request = new HttpDelete(url);
        addRequestHeader((HttpUriRequest) request, headerMap);

        return executeHttpRequest((HttpUriRequest) request);
    }


    public StreamClosedHttpResponse doDeleteGetStatusLine(String url, Map<String, String> headerMap) {
        HttpResponse response = doDelete(url, headerMap);
        if (response == null) {
            System.out.println("The response body is null.");
        }

        return (StreamClosedHttpResponse) response;
    }


    private static void addRequestHeader(HttpUriRequest request, Map<String, String> headerMap) {
        if (headerMap == null) {
            return;
        }

        for (String headerName : headerMap.keySet()) {
            if ("Content-Length".equalsIgnoreCase(headerName)) {
                continue;
            }

            String headerValue = headerMap.get(headerName);
            request.addHeader(headerName, headerValue);
        }
    }

    private HttpResponse executeHttpRequest(HttpUriRequest request) {
        Object object = null;

        try {
            object = httpClient.execute(request);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (object != null) {
                    object = new StreamClosedHttpResponse((HttpResponse) object);
                }
            } catch (IOException iOException) {
            }
        }


        return (HttpResponse) object;
    }


    public String getHttpResponseBody(HttpResponse response) throws UnsupportedOperationException, IOException {
        if (response == null) {
            return null;
        }

        String body = null;
        if (response instanceof StreamClosedHttpResponse) {
            body = ((StreamClosedHttpResponse) response).getContent();
        } else {
            HttpEntity entity = response.getEntity();
            if (entity != null && entity.isStreaming()) {
                String encoding = (entity.getContentEncoding() != null) ? entity
                        .getContentEncoding().getValue() : null;
                body = StreamUtil.inputStream2String(entity.getContent(),
                        encoding);
            }
        }
        return body;
    }
}
